package com.mfs.proxy.core.server.reactor;

import com.mfs.proxy.core.exceptions.ProxyException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * 服务端服务 reactor
 * 监听代理服务器服务端口，受理客户端的注册请求
 * @author mfs
 * @date 2022/07/10
 * */
public class ServerReactor implements Runnable {
    private final static Logger logger = LoggerFactory.getLogger(ServerReactor.class);
    private Selector serverSelector;
    public ServerReactor(String ip, int port) {
        try {
            serverSelector = Selector.open();
            ServerSocketChannel serverChannel = ServerSocketChannel.open();
            serverChannel.bind(new InetSocketAddress(ip, port));
            serverChannel.configureBlocking(false);
            serverChannel.register(serverSelector, SelectionKey.OP_ACCEPT);
        } catch (Exception e) {
            throw new ProxyException(e);
        }
    }

    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                serverSelector.select(100);
                if (Thread.currentThread().isInterrupted()) {
                    continue;
                }
                Iterator<SelectionKey> iterator = serverSelector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();
                    processAcceptable(selectionKey);
                    iterator.remove();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 处理连接请求，非连接请求会被忽略
     * */
    private void processAcceptable(SelectionKey selectionKey) {
        if (!(selectionKey.isValid() && selectionKey.isAcceptable())) {
            return;
        }
        ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
        SocketChannel clientChannel = null;
        try {
            clientChannel = serverSocketChannel.accept();
            clientChannel.configureBlocking(false);
            SubServerReactor.register(clientChannel);
        } catch (IOException e) {
            logger.error("处理连接请求失败", e);
            if (clientChannel != null) {
                try {
                    clientChannel.close();
                } catch (IOException ioException) {
                    logger.error("关闭客户端通道失败", e);
                }
            }
        }
    }
}
